package com.hyc.gchatsystem.websocket;


import com.google.gson.Gson;
import com.hyc.gchatsystem.enums.ReqType;
import com.hyc.gchatsystem.enums.RespType;
import com.hyc.gchatsystem.mapper.LocalData;
import com.hyc.gchatsystem.medel.GroupModel;
import com.hyc.gchatsystem.medel.ReqModel;
import com.hyc.gchatsystem.medel.RespModel;
import com.hyc.gchatsystem.medel.UserModel;
import com.hyc.gchatsystem.service.ChatService;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;


// 泛型 代表的是处理数据的单位
// TextWebSocketFrame 是文本信息帧
@Component
@ChannelHandler.Sharable
public class WebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    @Autowired
    private ChatService chatService;

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        System.out.println("msg : " + msg.text());
        // 获取请求数据  解析json形式
        ReqModel model = new Gson().fromJson(msg.text(), ReqModel.class);
        RespModel respModel = new RespModel();

        //设置用户信息
        respModel.setUid(model.getUid());
        respModel.setNickname(model.getNickname());

        //获取当前时间
        LocalDateTime now = LocalDateTime.now();
        String date = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        respModel.setDate(date);

        //bridge 初始值 要默认空值
        List<String> defaultList = new ArrayList<>();
        respModel.setBridge(defaultList);
        // 默认类型
        respModel.setType(RespType.OPERA.getNum());
        //判断请求类型
        ReqType type = ReqType.getTypeByNum(model.getType());
        switch (type) {
            case CONN:
                System.out.println(model.getNickname() + ": 用户上线了");
                //记录并返回在线用户列表 以及已经创建的群组列表
                //记录用户和通道的关联关系
                LocalData.channelUserUrl.put(model.getUid(), ctx.channel());
                chatService.addUser(model, respModel);
                break;
            case CANCEL:
                System.out.println(model.getNickname() + ": 用户下线了");
                LocalData.channelUserUrl.remove(LocalData.channelUserUrl.get(model.getUid()));
                chatService.delUser(model, respModel);
                break;
            case ADD_GROUP:
                System.out.println(model.getNickname() + "用户创建了群组" + model.getGroupName());
                chatService.addGroup(model, respModel);
                break;
            case JOIN_GROUP:
                System.out.println(model.getNickname() + "用户加入了群组" + model.getGroupName());
                chatService.joinGroup(model, respModel);
                break;
            case SEND_MSG:
                //识别响应类型 消息类型是更改
                respModel.setType(RespType.MSG.getNum());

                //判断一对一消息还是一对多消息
                if (model.getBridge().size() == 0) {
                    //    一对多
                    chatService.sendGroupMsg(model, respModel);
                } else {
                    chatService.sendPrivateMsg(model, respModel);
                }
                break;
            default:
        }

        System.out.println(new Gson().toJson(respModel));
        if (respModel.getType() == RespType.OPERA.getNum()) {
            List<Channel> channels = LocalData.getAllChannels();
            notifyChannels(channels, respModel);
            return;
        }
        //    根据一对一 或者一对多的类型来找到接受通知的用户
        if (model.getBridge().size() > 0) {
            //  代表一对一,只需要通知自身和需要接受消息的用户
            String selfId = model.getBridge().get(0);
            Channel selfChannel = LocalData.channelUserUrl.get(selfId);

            //接受信息的通道
            String otherId = model.getBridge().get(1);
            Channel otherChannel = LocalData.channelUserUrl.get(otherId);

            List<Channel> channels = new ArrayList<>();
            channels.add(selfChannel);
            channels.add(otherChannel);
            notifyChannels(channels, respModel);
            return;
        }
        //    一对多群组消息
        List<Channel> channels = new ArrayList<>();
        //    通过群id来找到群对象 获取用户列表 根据列表uid 获取对应的通道
        GroupModel groupModel = LocalData.getGroupById(model.getGroupId());
        for (UserModel userModel : groupModel.getUsers()) {
            Channel channel = LocalData.channelUserUrl.get(userModel.getUid());
            channels.add(channel);
        }
        notifyChannels(channels, respModel);
    }

    private void notifyChannels(List<Channel> channels, RespModel respModel) {
        for (Channel channel : channels) {
            TextWebSocketFrame resp = new TextWebSocketFrame(new Gson().toJson(respModel));
            channel.writeAndFlush(resp);
        }
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        //下线
        LocalData.channellist.remove(ctx.channel());
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        //上线
        LocalData.channellist.add(ctx.channel());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
    }
}
